<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>SQL日志监控面板</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        html {
            scroll-behavior: smooth;
        }

        /* 页面加载动画 */
        .page-loader {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            display: flex;
            justify-content: center;
            align-items: center;
            z-index: 9999;
            transition: opacity 0.5s ease;
        }

        .page-loader.fade-out {
            opacity: 0;
            pointer-events: none;
        }

        .loader-spinner {
            width: 60px;
            height: 60px;
            border: 4px solid rgba(255, 255, 255, 0.3);
            border-top: 4px solid white;
            border-radius: 50%;
            animation: spin 1s linear infinite;
        }

        @keyframes spin {
            0% {
                transform: rotate(0deg);
            }
            100% {
                transform: rotate(360deg);
            }
        }

        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Inter', sans-serif;
            background: #f8fafc;
            color: #2c3e50;
            min-height: 100vh;
        }

                .header {
            background: rgba(255, 255, 255, 0.95);
            backdrop-filter: blur(20px);
            -webkit-backdrop-filter: blur(20px);
            color: #2c3e50;
            padding: 1rem 1.5rem;
            display: flex;
            justify-content: space-between;
            align-items: center;
            box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
            border: 1px solid rgba(255, 255, 255, 0.2);
            border-radius: 12px;
            margin: 1rem;
        }
        
        .header h1 {
            font-size: 1.4rem;
            display: flex;
            align-items: center;
            gap: 0.5rem;
            font-weight: 600;
            color: #2c3e50;
        }

                .header-actions {
            display: flex;
            gap: 0.75rem;
            align-items: center;
        }
        
        .druid-link {
            display: inline-flex;
            align-items: center;
            gap: 0.5rem;
            background: #1e90ff;
            color: white;
            padding: 0.5rem 1rem;
            border-radius: 8px;
            font-size: 0.8rem;
            font-weight: 500;
            text-decoration: none;
            transition: all 0.3s ease;
        }
        
        .druid-link:hover {
            background: #1a7ee3;
            transform: translateY(-1px);
            box-shadow: 0 4px 12px rgba(30, 144, 255, 0.4);
        }
        
        .btn {
            padding: 0.5rem 1rem;
            border: 1px solid transparent;
            border-radius: 8px;
            cursor: pointer;
            font-size: 0.8rem;
            font-weight: 500;
            transition: all 0.3s ease;
            position: relative;
            overflow: hidden;
        }

        .btn::before {
            content: '';
            position: absolute;
            top: 0;
            left: -100%;
            width: 100%;
            height: 100%;
            background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
            transition: left 0.5s;
        }

        .btn:hover::before {
            left: 100%;
        }

        .btn-primary {
            background: #8b92ff;
            color: white;
            border-color: transparent;
        }

        .btn-primary:hover {
            background: #7980ff;
            transform: translateY(-1px);
            box-shadow: 0 4px 12px rgba(139, 146, 255, 0.4);
        }

                .btn-danger {
            background: #95a5a6;
            color: white;
            border-color: transparent;
        }
        
        .btn-danger:hover {
            background: #7f8c8d;
            transform: translateY(-1px);
            box-shadow: 0 4px 12px rgba(149, 165, 166, 0.3);
        }

                         .controls {
             background: rgba(255, 255, 255, 0.95);
             backdrop-filter: blur(20px);
             -webkit-backdrop-filter: blur(20px);
             padding: 1.25rem 1.5rem;
             border: 1px solid rgba(139, 146, 255, 0.1);
             border-radius: 12px 12px 0 0;
             box-shadow: 0 4px 16px rgba(139, 146, 255, 0.08);
             display: flex;
             gap: 1.25rem;
             align-items: center;
             flex-wrap: wrap;
             margin: 1rem 1rem 0 1rem;
             position: relative;
         }

                 .controls::before {
             content: '';
             position: absolute;
             top: 0;
             left: 0;
             right: 0;
             height: 2px;
             background: linear-gradient(90deg, transparent, #8b92ff, transparent);
             border-radius: 12px 12px 0 0;
         }

        .search-box {
            flex: 1;
            min-width: 320px;
            position: relative;
        }

        .search-box input {
            width: 100%;
            padding: 0.75rem 3rem 0.75rem 1.25rem;
            border: 2px solid rgba(139, 146, 255, 0.15);
            border-radius: 12px;
            font-size: 1rem;
            background: rgba(255, 255, 255, 0.9);
            backdrop-filter: blur(10px);
            color: #2c3e50;
            transition: all 0.3s ease;
            box-shadow: 0 4px 15px rgba(139, 146, 255, 0.05);
        }

        .search-box input:focus {
            outline: none;
            border-color: #8b92ff;
            background: rgba(255, 255, 255, 0.95);
            box-shadow: 0 0 0 3px rgba(139, 146, 255, 0.15);
        }

        .search-box input::placeholder {
            color: #8892b0;
        }

        .search-box .search-icon {
            position: absolute;
            right: 1rem;
            top: 50%;
            transform: translateY(-50%);
            color: #8b92ff;
            font-size: 1.1rem;
        }

        .filter-select {
            padding: 0.75rem 1rem;
            border: 2px solid rgba(139, 146, 255, 0.15);
            border-radius: 12px;
            font-size: 1rem;
            background: rgba(255, 255, 255, 0.9);
            backdrop-filter: blur(10px);
            color: #2c3e50;
            transition: all 0.3s ease;
            box-shadow: 0 4px 15px rgba(139, 146, 255, 0.05);
            cursor: pointer;
            min-width: 140px;
        }

        .filter-select:focus {
            outline: none;
            border-color: #8b92ff;
            background: rgba(255, 255, 255, 0.95);
            box-shadow: 0 0 0 3px rgba(139, 146, 255, 0.15);
        }

                         .stats {
             background: linear-gradient(135deg, #8b92ff 0%, #7980ff 100%);
             padding: 1.5rem;
             color: white;
             display: grid;
             grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
             gap: 1rem;
             margin: 0 1rem;
             border-radius: 12px;
             box-shadow: 0 4px 16px rgba(139, 146, 255, 0.12);
         }
         
         .stat-item {
             background: rgba(255, 255, 255, 0.15);
             padding: 1rem;
             border-radius: 8px;
             text-align: center;
             backdrop-filter: blur(15px);
             border: 1px solid rgba(255, 255, 255, 0.3);
             transition: all 0.3s ease;
             position: relative;
             overflow: hidden;
         }

        .stat-item::before {
            content: '';
            position: absolute;
            top: 0;
            left: -100%;
            width: 100%;
            height: 100%;
            background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.1), transparent);
            transition: left 0.6s ease;
        }

                 .stat-item:hover {
             transform: translateY(-3px);
             background: rgba(255, 255, 255, 0.2);
             box-shadow: 0 6px 20px rgba(0, 0, 0, 0.15);
         }

        .stat-item:hover::before {
            left: 100%;
        }

                 .stat-icon {
             font-size: 2rem;
             margin-bottom: 0.75rem;
             display: block;
         }
         
         .stat-value {
             font-weight: bold;
             font-size: 1.6rem;
             margin-bottom: 0.25rem;
             display: block;
         }
         
         .stat-label {
             font-size: 0.8rem;
             opacity: 0.9;
         }

        .main-content {
            padding: 0 1rem 2rem 1rem;
        }

        .sql-logs {
            background: rgba(255, 255, 255, 0.95);
            backdrop-filter: blur(20px);
            -webkit-backdrop-filter: blur(20px);
            border: 1px solid rgba(255, 255, 255, 0.2);
            border-radius: 0 0 12px 12px;
            box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
            overflow: hidden;
        }

        .log-item {
            border-bottom: 1px solid rgba(255, 255, 255, 0.3);
            padding: 1.5rem;
            transition: all 0.3s ease;
            position: relative;
        }

        .log-item:hover {
            background: rgba(139, 146, 255, 0.06);
            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
        }

        .log-item::before {
            content: '';
            position: absolute;
            left: 0;
            top: 0;
            bottom: 0;
            width: 3px;
            background: #8b92ff;
            opacity: 0;
            transition: opacity 0.3s ease;
        }

        .log-item:hover::before {
            opacity: 1;
        }

        .log-item:last-child {
            border-bottom: none;
        }

        .log-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 0.5rem;
        }

        .log-meta {
            display: flex;
            gap: 1rem;
            align-items: center;
            font-size: 0.9rem;
            color: #666;
        }

        .sql-type {
            padding: 0.2rem 0.5rem;
            border-radius: 3px;
            font-size: 0.8rem;
            font-weight: bold;
        }

        .sql-type.SELECT {
            background: #e3f2fd;
            color: #1976d2;
        }

        .sql-type.INSERT {
            background: #e8f5e8;
            color: #388e3c;
        }

        .sql-type.UPDATE {
            background: #fff3e0;
            color: #f57c00;
        }

        .sql-type.DELETE {
            background: #ffebee;
            color: #d32f2f;
        }

        .performance {
            padding: 0.2rem 0.5rem;
            border-radius: 3px;
            font-size: 0.8rem;
            font-weight: bold;
        }

        .performance.fast {
            background: #e8f5e8;
            color: #388e3c;
        }

        .performance.medium {
            background: #fff3e0;
            color: #f57c00;
        }

        .performance.slow {
            background: #ffebee;
            color: #d32f2f;
        }

        .log-actions {
            display: flex;
            gap: 0.5rem;
        }

        .btn-small {
            padding: 0.5rem 1rem;
            font-size: 0.85rem;
            border: 1px solid #8b92ff;
            background: #8b92ff;
            color: white;
            border-radius: 6px;
            cursor: pointer;
            transition: all 0.2s ease;
            font-weight: 500;
        }

        .btn-small:hover {
            background: #7980ff;
            border-color: #7980ff;
            transform: translateY(-1px);
            box-shadow: 0 3px 8px rgba(139, 146, 255, 0.4);
        }

        .btn-small:active {
            transform: translateY(0);
            box-shadow: 0 1px 4px rgba(139, 146, 255, 0.3);
        }

        .sql-content {
            background: linear-gradient(135deg, rgba(248, 249, 250, 0.9) 0%, rgba(233, 236, 239, 0.9) 100%);
            backdrop-filter: blur(10px);
            padding: 1.5rem;
            border-radius: 12px;
            font-family: 'Fira Code', 'Consolas', 'Monaco', monospace;
            font-size: 0.9rem;
            line-height: 1.6;
            white-space: pre-wrap;
            word-break: break-all;
            margin-top: 1rem;
            border: 1px solid rgba(100, 108, 255, 0.2);
            box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05);
            position: relative;
        }

        .sql-content::before {
            content: '';
            position: absolute;
            left: 0;
            top: 0;
            bottom: 0;
            width: 4px;
            background: #646cff;
            border-radius: 0 2px 2px 0;
        }

        .sql-result {
            margin-top: 1.5rem;
            border: 1px solid rgba(100, 108, 255, 0.2);
            border-radius: 8px;
            overflow: hidden;
            background: rgba(255, 255, 255, 0.95);
            backdrop-filter: blur(10px);
            box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
        }

        .result-header {
            background: rgba(100, 108, 255, 0.08);
            padding: 1rem;
            border-bottom: 1px solid rgba(100, 108, 255, 0.2);
            display: flex;
            justify-content: space-between;
            align-items: center;
            cursor: pointer;
            transition: all 0.2s ease;
        }

        .result-header:hover {
            background: rgba(100, 108, 255, 0.12);
        }

        .result-toggle {
            display: flex;
            align-items: center;
            gap: 0.5rem;
        }

        .toggle-icon {
            transition: transform 0.3s ease;
            font-size: 0.8rem;
        }

        .toggle-icon.collapsed {
            transform: rotate(-90deg);
        }

        .result-info {
            font-size: 0.9rem;
            color: #6c757d;
        }

        .result-actions {
            display: flex;
            gap: 0.5rem;
        }

        .result-table-container {
            max-height: 500px;
            overflow: auto;
            border: 1px solid rgba(100, 108, 255, 0.2);
            border-radius: 8px;
            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
            backdrop-filter: blur(10px);
        }

        .result-table {
            width: 100%;
            border-collapse: collapse;
            font-size: 0.85rem;
            table-layout: fixed;
            background: rgba(255, 255, 255, 0.9);
        }

        .result-table th,
        .result-table td {
            padding: 0.75rem;
            text-align: left;
            border-right: 1px solid rgba(100, 108, 255, 0.1);
            border-bottom: 1px solid rgba(100, 108, 255, 0.1);
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
            position: relative;
            transition: all 0.2s ease;
        }

        .result-table th {
            background: linear-gradient(135deg, #646cff 0%, #646cff 100%);
            font-weight: 600;
            color: white;
            position: sticky;
            top: 0;
            z-index: 10;
            min-width: 80px;
            max-width: 200px;
            width: auto;
            text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
        }

        .result-table td {
            min-width: 80px;
            max-width: 200px;
            cursor: pointer;
            color: #2c3e50;
        }

        .result-table tr:hover {
            background: rgba(100, 108, 255, 0.08);
            box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
        }

        .result-table tr:nth-child(even) {
            background: rgba(248, 249, 250, 0.5);
        }

        .result-table tr:nth-child(even):hover {
            background: rgba(100, 108, 255, 0.08);
        }

        /* 列宽度优化 */
        .result-table th:first-child,
        .result-table td:first-child {
            width: 60px;
            min-width: 60px;
            max-width: 60px;
        }

        .result-table th.col-id,
        .result-table td.col-id {
            width: 60px;
            min-width: 60px;
            max-width: 60px;
        }

        .result-table th.col-name,
        .result-table td.col-name {
            width: 120px;
            min-width: 120px;
            max-width: 180px;
        }

        .result-table th.col-time,
        .result-table td.col-time {
            width: 140px;
            min-width: 140px;
            max-width: 140px;
        }

        .result-table th.col-text,
        .result-table td.col-text {
            width: 150px;
            min-width: 100px;
            max-width: 250px;
        }

        /* 单元格内容展开 */
        .cell-content {
            position: relative;
        }

        .cell-expanded {
            white-space: normal !important;
            word-break: break-all;
            max-height: none;
        }

        .cell-tooltip {
            position: absolute;
            top: 100%;
            left: 0;
            background: #333;
            color: white;
            padding: 0.5rem;
            border-radius: 4px;
            font-size: 0.75rem;
            max-width: 300px;
            word-break: break-all;
            z-index: 1000;
            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
            display: none;
        }

        .execute-loading {
            text-align: center;
            padding: 2rem;
            color: #6c757d;
        }

        .execute-error {
            background: #f8d7da;
            color: #721c24;
            padding: 1rem;
            border-radius: 5px;
            margin: 1rem;
        }

        .toast {
            position: fixed;
            top: 20px;
            right: 20px;
            background: #333;
            color: white;
            padding: 1rem 1.5rem;
            border-radius: 8px;
            z-index: 1000;
            transform: translateX(100%);
            transition: transform 0.3s ease;
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
            font-size: 0.9rem;
            max-width: 300px;
        }

        .toast.show {
            transform: translateX(0);
        }

        .toast.success {
            background: linear-gradient(135deg, #28a745 0%, #20c997 100%);
        }

        .toast.error {
            background: linear-gradient(135deg, #dc3545 0%, #c82333 100%);
        }

        .no-logs {
            text-align: center;
            padding: 3rem;
            color: #999;
        }

        .loading {
            text-align: center;
            padding: 2rem;
            color: #999;
        }

        .toast {
            position: fixed;
            top: 20px;
            right: 20px;
            background: #333;
            color: white;
            padding: 1rem;
            border-radius: 5px;
            z-index: 1000;
            transform: translateX(100%);
            transition: transform 0.3s;
        }

        .toast.show {
            transform: translateX(0);
        }

        .toast.success {
            background: #27ae60;
        }

        .toast.error {
            background: #e74c3c;
        }

        .login-overlay {
            position: fixed;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background: linear-gradient(135deg, rgba(139, 146, 255, 0.95) 0%, rgba(121, 128, 255, 0.95) 100%);
            backdrop-filter: blur(15px);
            display: flex;
            align-items: center;
            justify-content: center;
            z-index: 2000;
            overflow: hidden;
        }

        .login-overlay::before {
            content: '';
            position: absolute;
            top: -50%;
            left: -50%;
            width: 200%;
            height: 200%;
            background: radial-gradient(circle, rgba(255, 255, 255, 0.1) 1px, transparent 1px);
            background-size: 50px 50px;
            animation: float 20s linear infinite;
            z-index: -1;
        }

        @keyframes float {
            0% { transform: translate(-50%, -50%) rotate(0deg); }
            100% { transform: translate(-50%, -50%) rotate(360deg); }
        }

        .login-container {
            background: rgba(255, 255, 255, 0.95);
            backdrop-filter: blur(20px);
            padding: 2.5rem;
            border-radius: 20px;
            box-shadow: 0 20px 60px rgba(0, 0, 0, 0.15), 0 0 0 1px rgba(255, 255, 255, 0.3);
            width: 100%;
            max-width: 420px;
            position: relative;
            overflow: hidden;
            animation: fadeInUp 0.6s ease-out;
        }

        @keyframes fadeInUp {
            from {
                opacity: 0;
                transform: translateY(30px);
            }
            to {
                opacity: 1;
                transform: translateY(0);
            }
        }
        
        .login-container::before {
            content: '';
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            height: 3px;
            background: linear-gradient(90deg, #8b92ff, #7980ff, #8b92ff);
            background-size: 200% 100%;
            animation: shimmer 3s ease-in-out infinite;
        }
        
        @keyframes shimmer {
            0%, 100% { background-position: 200% 0; }
            50% { background-position: -200% 0; }
        }

        .login-container::after {
            content: '';
            position: absolute;
            top: 20px;
            right: 20px;
            width: 60px;
            height: 60px;
            background: linear-gradient(45deg, rgba(139, 146, 255, 0.1), rgba(121, 128, 255, 0.1));
            border-radius: 50%;
            z-index: -1;
        }

        .login-form-decoration {
            position: absolute;
            bottom: 20px;
            left: 20px;
            width: 40px;
            height: 40px;
            background: linear-gradient(45deg, rgba(139, 146, 255, 0.08), rgba(121, 128, 255, 0.08));
            border-radius: 50%;
            z-index: -1;
        }

        .login-header {
            text-align: center;
            margin-bottom: 2.5rem;
            position: relative;
            z-index: 1;
        }

        .login-header h2 {
            color: #2c3e50;
            font-size: 1.8rem;
            margin-bottom: 0.75rem;
            font-weight: 700;
            background: linear-gradient(135deg, #8b92ff 0%, #7980ff 100%);
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
            background-clip: text;
        }

        .login-header p {
            color: #64748b;
            font-size: 0.95rem;
            font-weight: 400;
            line-height: 1.5;
        }

        .form-group {
            margin-bottom: 1.5rem;
            position: relative;
        }

        .form-group label {
            display: block;
            margin-bottom: 0.75rem;
            color: #374151;
            font-weight: 600;
            font-size: 0.9rem;
            letter-spacing: 0.025em;
        }

        .form-group input {
            width: 100%;
            padding: 1rem 1.25rem;
            border: 2px solid rgba(139, 146, 255, 0.2);
            border-radius: 12px;
            font-size: 1rem;
            background: rgba(255, 255, 255, 0.8);
            backdrop-filter: blur(10px);
            transition: all 0.3s ease;
            color: #2c3e50;
        }

        .form-group input:focus {
            outline: none;
            border-color: #8b92ff;
            background: rgba(255, 255, 255, 0.95);
            box-shadow: 0 0 0 4px rgba(139, 146, 255, 0.1);
            transform: translateY(-1px);
        }

        .form-group input::placeholder {
            color: #9ca3af;
        }

        .login-btn {
            width: 100%;
            padding: 1rem 1.5rem;
            background: linear-gradient(135deg, #8b92ff 0%, #7980ff 100%);
            color: white;
            border: none;
            border-radius: 12px;
            font-size: 1.05rem;
            font-weight: 600;
            cursor: pointer;
            transition: all 0.3s ease;
            position: relative;
            overflow: hidden;
            box-shadow: 0 4px 20px rgba(139, 146, 255, 0.3);
        }

        .login-btn::before {
            content: '';
            position: absolute;
            top: 0;
            left: -100%;
            width: 100%;
            height: 100%;
            background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
            transition: left 0.5s;
        }

        .login-btn:hover {
            transform: translateY(-2px);
            box-shadow: 0 6px 25px rgba(139, 146, 255, 0.4);
        }

        .login-btn:hover::before {
            left: 100%;
        }

        .login-btn:active {
            transform: translateY(0);
        }

        .login-btn:disabled {
            opacity: 0.7;
            cursor: not-allowed;
            transform: none;
        }

        .login-btn.loading {
            position: relative;
            color: transparent;
        }

        .login-btn.loading::after {
            content: '';
            position: absolute;
            top: 50%;
            left: 50%;
            width: 20px;
            height: 20px;
            margin: -10px 0 0 -10px;
            border: 2px solid rgba(255, 255, 255, 0.3);
            border-top: 2px solid white;
            border-radius: 50%;
            animation: spin 1s linear infinite;
        }

        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }

        .error-message {
            color: #ef4444;
            text-align: center;
            margin-top: 1.5rem;
            display: none;
            background: rgba(239, 68, 68, 0.1);
            padding: 0.75rem 1rem;
            border-radius: 8px;
            border: 1px solid rgba(239, 68, 68, 0.2);
            font-size: 0.9rem;
            font-weight: 500;
        }

        @media (max-width: 768px) {
            .header {
                flex-direction: column;
                gap: 1rem;
                text-align: center;
            }

            .controls {
                flex-direction: column;
                align-items: stretch;
            }

            .search-box {
                min-width: auto;
            }

            .stats {
                justify-content: center;
            }

            .log-header {
                flex-direction: column;
                align-items: flex-start;
                gap: 0.5rem;
            }

            .log-meta {
                flex-wrap: wrap;
            }
        }
    </style>
</head>
<body>
<!-- 页面加载器 -->
<div class="page-loader" id="pageLoader">
    <div class="loader-spinner"></div>
</div>

<!-- 登录遮罩层 -->
<div id="loginOverlay" class="login-overlay" style="display: none;">
    <div class="login-container">
        <div class="login-form-decoration"></div>
        <div class="login-header">
            <h2>🔍 SQL日志系统</h2>
            <p>请输入登录凭据以访问SQL监控面板</p>
        </div>

        <form id="loginForm">
            <div class="form-group">
                <label for="username">👤 用户名</label>
                <input type="text" id="username" name="username" placeholder="请输入用户名" required>
            </div>

            <div class="form-group">
                <label for="password">🔐 密码</label>
                <input type="password" id="password" name="password" placeholder="请输入密码" required>
            </div>

            <button type="submit" class="login-btn">登录</button>

            <div id="errorMessage" class="error-message">
                用户名或密码错误
            </div>
        </form>
    </div>
</div>

    <!-- 主页面内容 -->
<div id="mainContent" style="display: none;">
    <div class="header">
        <h1>🔍 SQL日志监控面板</h1>
        <div class="header-actions">
            <a href="/druid/login.html" target="_blank" class="druid-link">📊 Druid监控</a>
            <button class="btn btn-primary" onclick="refreshLogs()">🔄 刷新</button>
            <button class="btn btn-primary" onclick="clearLogs()">🗑️ 清空日志</button>
            <button class="btn btn-danger" onclick="logout()">🚪 退出</button>
        </div>
    </div>

    <div class="stats">
        <div class="stat-item">
            <div class="stat-icon">📊</div>
            <div class="stat-value" id="totalCount">0</div>
            <div class="stat-label">总记录数</div>
        </div>
        <div class="stat-item">
            <div class="stat-icon">⚡</div>
            <div class="stat-value" id="fastCount">0</div>
            <div class="stat-label">快速查询</div>
        </div>
        <div class="stat-item">
            <div class="stat-icon">⚠️</div>
            <div class="stat-value" id="mediumCount">0</div>
            <div class="stat-label">中等查询</div>
        </div>
        <div class="stat-item">
            <div class="stat-icon">🐌</div>
            <div class="stat-value" id="slowCount">0</div>
            <div class="stat-label">慢查询</div>
        </div>
    </div>

    <div class="controls">
        <div class="search-box">
            <input type="text" id="searchInput" placeholder="搜索SQL语句、表名或SQL类型..." oninput="filterLogs()">
            <span class="search-icon">🔍</span>
        </div>
        <select class="filter-select" id="typeFilter" onchange="filterLogs()">
            <option value="">所有类型</option>
            <option value="SELECT">SELECT</option>
            <option value="INSERT">INSERT</option>
            <option value="UPDATE">UPDATE</option>
            <option value="DELETE">DELETE</option>
        </select>
        <select class="filter-select" id="performanceFilter" onchange="filterLogs()">
            <option value="">所有性能</option>
            <option value="fast">快速 (&lt;500ms)</option>
            <option value="medium">中等 (500-1000ms)</option>
            <option value="slow">慢查询 (&gt;1000ms)</option>
        </select>
    </div>

    <div class="main-content">
        <div class="sql-logs" id="sqlLogs">
            <div class="loading">
                正在加载SQL日志...
            </div>
        </div>
    </div>
</div>

<script>
    let allLogs = [];
    let filteredLogs = [];
    let isAuthenticated = false;

    // 页面加载时检查认证状态
    document.addEventListener('DOMContentLoaded', function () {
        // 页面加载完成后隐藏加载器
        setTimeout(() => {
            const pageLoader = document.getElementById('pageLoader');
            pageLoader.classList.add('fade-out');
            setTimeout(() => {
                pageLoader.style.display = 'none';
            }, 500);
        }, 1000);

        checkAuthStatus();
    });

    // 检查认证状态
    function checkAuthStatus() {
        fetch('/sqlLog/checkAuth')
            .then(response => response.text())
            .then(result => {
                if (result === 'authenticated') {
                    showMainContent();
                } else {
                    showLoginOverlay();
                }
            })
            .catch(error => {
                console.error('检查认证状态失败:', error);
                showLoginOverlay();
            });
    }

    // 显示登录遮罩
    function showLoginOverlay() {
        document.getElementById('loginOverlay').style.display = 'flex';
        document.getElementById('mainContent').style.display = 'none';
        isAuthenticated = false;
    }

    // 显示主内容
    function showMainContent() {
        document.getElementById('loginOverlay').style.display = 'none';
        document.getElementById('mainContent').style.display = 'block';
        isAuthenticated = true;
        loadSqlLogs();
        // 每30秒自动刷新
        setInterval(loadSqlLogs, 30000);
    }

    // 登录表单提交
    document.getElementById('loginForm').addEventListener('submit', function (e) {
        e.preventDefault();

        const username = document.getElementById('username').value;
        const password = document.getElementById('password').value;
        const errorMessage = document.getElementById('errorMessage');
        const loginBtn = document.querySelector('.login-btn');

        // 显示加载状态
        loginBtn.classList.add('loading');
        loginBtn.disabled = true;
        errorMessage.style.display = 'none';

        fetch('/sqlLog/login', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded',
            },
            body: `username=${encodeURIComponent(username)}&password=${encodeURIComponent(password)}`
        })
            .then(response => response.text())
            .then(result => {
                if (result === 'success') {
                    showMainContent();
                    errorMessage.style.display = 'none';
                } else {
                    errorMessage.style.display = 'block';
                    errorMessage.textContent = '用户名或密码错误，请重试';
                }
            })
            .catch(error => {
                console.error('登录失败:', error);
                errorMessage.style.display = 'block';
                errorMessage.textContent = '登录失败，请检查网络连接';
            })
            .finally(() => {
                // 恢复按钮状态
                loginBtn.classList.remove('loading');
                loginBtn.disabled = false;
            });
    });

    // 加载SQL日志
    function loadSqlLogs() {
        if (!isAuthenticated) return;

        fetch('/sqlLog/logs')
            .then(response => response.json())
            .then(data => {
                allLogs = data.logs || [];
                updateStats();
                filterLogs();
            })
            .catch(error => {
                console.error('加载日志失败:', error);
                showToast('加载日志失败', 'error');
            });
    }

    // 更新统计信息
    function updateStats() {
        const total = allLogs.length;
        const fast = allLogs.filter(log => log.elapsedTime < 500).length;
        const medium = allLogs.filter(log => log.elapsedTime >= 500 && log.elapsedTime < 1000).length;
        const slow = allLogs.filter(log => log.elapsedTime >= 1000).length;

        document.getElementById('totalCount').textContent = total;
        document.getElementById('fastCount').textContent = fast;
        document.getElementById('mediumCount').textContent = medium;
        document.getElementById('slowCount').textContent = slow;
    }

    // 过滤日志
    function filterLogs() {
        const searchText = document.getElementById('searchInput').value.toLowerCase();
        const typeFilter = document.getElementById('typeFilter').value;
        const performanceFilter = document.getElementById('performanceFilter').value;

        filteredLogs = allLogs.filter(log => {
            // 搜索过滤
            const matchesSearch = !searchText ||
                log.sql.toLowerCase().includes(searchText) ||
                (log.tableName && log.tableName.toLowerCase().includes(searchText)) ||
                log.sqlType.toLowerCase().includes(searchText);

            // 类型过滤
            const matchesType = !typeFilter || log.sqlType === typeFilter;

            // 性能过滤
            let matchesPerformance = true;
            if (performanceFilter === 'fast') {
                matchesPerformance = log.elapsedTime < 500;
            } else if (performanceFilter === 'medium') {
                matchesPerformance = log.elapsedTime >= 500 && log.elapsedTime < 1000;
            } else if (performanceFilter === 'slow') {
                matchesPerformance = log.elapsedTime >= 1000;
            }

            return matchesSearch && matchesType && matchesPerformance;
        });

        renderLogs();
    }

    // 渲染日志列表
    function renderLogs() {
        const container = document.getElementById('sqlLogs');

        if (filteredLogs.length === 0) {
            container.innerHTML = '<div class="no-logs">暂无SQL日志记录</div>';
            return;
        }

        const html = filteredLogs.map(log => {
            const time = new Date(log.timestamp).toLocaleString();
            const performanceClass = getPerformanceClass(log.elapsedTime);
            const performanceText = getPerformanceText(log.elapsedTime);

            return `
                    <div class="log-item">
                        <div class="log-header">
                            <div class="log-meta">
                                <span class="sql-type ${log.sqlType}">${log.sqlType}</span>
                                <span class="performance ${performanceClass}">${performanceText}</span>
                                <span>📅 ${time}</span>
                                ${log.tableName ? `<span>📋 ${log.tableName}</span>` : ''}
                            </div>
                                                         <div class="log-actions">
                                 <button class="btn-small" onclick="copySql(\`${log.sql.replace(/`/g, '\\`')}\`)">📋 复制</button>
                                 <button class="btn-small" onclick="formatSql(\`${log.sql.replace(/`/g, '\\`')}\`)">🎨 格式化</button>
                                 <button class="btn-small" onclick="executeSql(\`${log.sql.replace(/`/g, '\\`')}\`, '${log.timestamp}')">▶️ 执行查询</button>
                             </div>
                        </div>
                                                 <div class="sql-content">${escapeHtml(log.sql)}</div>
                         <div id="result-${log.timestamp}" class="sql-result" style="display: none;"></div>
                     </div>
                `;
        }).join('');

        container.innerHTML = html;
    }

    // 获取性能等级样式类
    function getPerformanceClass(elapsedTime) {
        if (elapsedTime < 500) return 'fast';
        if (elapsedTime < 1000) return 'medium';
        return 'slow';
    }

    // 获取性能等级文本
    function getPerformanceText(elapsedTime) {
        if (elapsedTime < 500) return `⚡ ${elapsedTime}ms`;
        if (elapsedTime < 1000) return `⚠️ ${elapsedTime}ms`;
        return `🐌 ${elapsedTime}ms`;
    }

    // 转义HTML
    function escapeHtml(text) {
        const div = document.createElement('div');
        div.textContent = text;
        return div.innerHTML;
    }

    // 复制SQL
    function copySql(sql) {
        navigator.clipboard.writeText(sql).then(() => {
            showToast('SQL已复制到剪贴板', 'success');
        }).catch(err => {
            console.error('复制失败:', err);
            showToast('复制失败', 'error');
        });
    }

    // 格式化SQL
    function formatSql(sql) {
        // 简单的SQL格式化
        const formatted = sql
            .replace(/\bSELECT\b/gi, '\nSELECT')
            .replace(/\bFROM\b/gi, '\nFROM')
            .replace(/\bWHERE\b/gi, '\nWHERE')
            .replace(/\bAND\b/gi, '\n  AND')
            .replace(/\bOR\b/gi, '\n  OR')
            .replace(/\bORDER BY\b/gi, '\nORDER BY')
            .replace(/\bGROUP BY\b/gi, '\nGROUP BY')
            .replace(/\bHAVING\b/gi, '\nHAVING')
            .replace(/\bLIMIT\b/gi, '\nLIMIT')
            .trim();

        navigator.clipboard.writeText(formatted).then(() => {
            showToast('格式化SQL已复制到剪贴板', 'success');
        }).catch(error => {
            console.error('复制失败:', error);
            showToast('复制失败', 'error');
        });
    }

    // 执行SQL查询
    function executeSql(sql, timestamp) {
        const resultContainer = document.getElementById(`result-${timestamp}`);

        // 显示加载状态
        resultContainer.style.display = 'block';
        resultContainer.innerHTML = '<div class="execute-loading">🔄 正在执行查询...</div>';

        fetch('/sqlLog/execute', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify({sql: sql})
        })
            .then(response => response.json())
            .then(data => {
                if (data.success) {
                    displayExecuteResult(resultContainer, data.data, data.executionTime);
                    showToast('查询执行成功', 'success');
                } else {
                    displayExecuteError(resultContainer, data.message);
                    showToast('查询执行失败', 'error');
                }
            })
            .catch(error => {
                console.error('执行失败:', error);
                displayExecuteError(resultContainer, '网络错误或服务器异常');
                showToast('执行失败', 'error');
            });
    }

    // 显示执行结果
    function displayExecuteResult(container, data, executionTime) {
        const resultId = 'result_' + Date.now();

        if (!data || data.length === 0) {
            container.innerHTML = `
                     <div class="result-header" onclick="toggleResult('${resultId}')">
                         <div class="result-toggle">
                             <span class="toggle-icon">🔽</span>
                             <div class="result-info">查询成功，但没有返回数据 (${executionTime}ms)</div>
                         </div>
                         <div class="result-actions" onclick="event.stopPropagation()">
                             <button class="btn-small" onclick="closeResult(this)">❌ 关闭</button>
                         </div>
                     </div>
                     <div id="${resultId}" class="result-content">
                         <div style="padding: 2rem; text-align: center; color: #6c757d;">无数据</div>
                     </div>
                 `;
            return;
        }

        const columns = Object.keys(data[0]);

        // 智能判断列类型并设置样式类
        const getColumnClass = (colName) => {
            const lowerName = colName.toLowerCase();
            if (lowerName === 'id' || lowerName.endsWith('_id')) return 'col-id';
            if (lowerName.includes('time') || lowerName.includes('date')) return 'col-time';
            if (lowerName.includes('name') || lowerName.includes('title')) return 'col-name';
            return 'col-text';
        };

        let tableHtml = `
                 <div class="result-header" onclick="toggleResult('${resultId}')">
                     <div class="result-toggle">
                         <span class="toggle-icon">🔽</span>
                         <div class="result-info">返回 ${data.length} 行记录 (${executionTime}ms)</div>
                     </div>
                     <div class="result-actions" onclick="event.stopPropagation()">
                         <button class="btn-small" onclick="exportResult(this)">📥 导出</button>
                         <button class="btn-small" onclick="closeResult(this)">❌ 关闭</button>
                     </div>
                 </div>
                 <div id="${resultId}" class="result-content">
                     <div class="result-table-container">
                         <table class="result-table">
                             <thead>
                                 <tr>
             `;

        columns.forEach(col => {
            const colClass = getColumnClass(col);
            tableHtml += `<th class="${colClass}" title="${escapeHtml(col)}">${escapeHtml(col)}</th>`;
        });

        tableHtml += '</tr></thead><tbody>';

        data.forEach((row, rowIndex) => {
            tableHtml += '<tr>';
            columns.forEach(col => {
                const colClass = getColumnClass(col);
                const value = row[col];
                const displayValue = value === null ? '<em style="color: #6c757d;">NULL</em>' :
                    value === undefined ? '<em style="color: #6c757d;">UNDEFINED</em>' :
                        escapeHtml(String(value));

                const fullValue = value === null ? 'NULL' :
                    value === undefined ? 'UNDEFINED' : String(value);

                tableHtml += `<td class="${colClass}" title="${escapeHtml(fullValue)}"
                                      onclick="toggleCellContent(this, '${escapeHtml(fullValue)}')"
                                      data-full-value="${escapeHtml(fullValue)}">
                                      ${displayValue}
                                   </td>`;
            });
            tableHtml += '</tr>';
        });

        tableHtml += '</tbody></table></div></div>';
        container.innerHTML = tableHtml;

        // 保存数据用于导出
        container.dataset.resultData = JSON.stringify(data);
    }

    // 显示执行错误
    function displayExecuteError(container, errorMessage) {
        container.innerHTML = `
                 <div class="result-header">
                     <div class="result-info" style="color: #dc3545;">查询执行失败</div>
                     <div class="result-actions">
                         <button class="btn-small" onclick="closeResult(this)">❌ 关闭</button>
                     </div>
                 </div>
                 <div class="execute-error">${escapeHtml(errorMessage)}</div>
             `;
    }

    // 切换结果展开/折叠
    function toggleResult(resultId) {
        const content = document.getElementById(resultId);
        const icon = content.previousElementSibling.querySelector('.toggle-icon');

        if (content.style.display === 'none') {
            content.style.display = 'block';
            icon.textContent = '🔽';
            icon.classList.remove('collapsed');
        } else {
            content.style.display = 'none';
            icon.textContent = '▶️';
            icon.classList.add('collapsed');
        }
    }

    // 切换单元格内容显示
    function toggleCellContent(cell, fullValue) {
        const isExpanded = cell.classList.contains('cell-expanded');

        if (isExpanded) {
            // 收起
            cell.classList.remove('cell-expanded');
            cell.style.whiteSpace = 'nowrap';
            cell.style.overflow = 'hidden';
            cell.style.textOverflow = 'ellipsis';
        } else {
            // 展开
            cell.classList.add('cell-expanded');
            cell.style.whiteSpace = 'normal';
            cell.style.overflow = 'visible';
            cell.style.textOverflow = 'unset';
            cell.style.wordBreak = 'break-all';
        }
    }

    // 关闭结果
    function closeResult(button) {
        const container = button.closest('.sql-result');
        container.style.display = 'none';
    }

    // 导出结果
    function exportResult(button) {
        const container = button.closest('.sql-result');
        const dataStr = container.dataset.resultData;

        if (!dataStr) {
            showToast('没有可导出的数据', 'error');
            return;
        }

        try {
            const data = JSON.parse(dataStr);
            const columns = Object.keys(data[0]);
            let csvContent = columns.join(',') + '\n';

            data.forEach(row => {
                const values = columns.map(col => {
                    const value = row[col];
                    if (value === null || value === undefined) return '';
                    const str = String(value);
                    // 如果包含逗号或引号，需要用引号包围并转义
                    if (str.includes(',') || str.includes('"') || str.includes('\n')) {
                        return '"' + str.replace(/"/g, '""') + '"';
                    }
                    return str;
                });
                csvContent += values.join(',') + '\n';
            });

            // 创建下载链接
            const blob = new Blob([csvContent], {type: 'text/csv;charset=utf-8;'});
            const link = document.createElement('a');
            link.href = URL.createObjectURL(blob);
            link.download = `sql_results_${new Date().getTime()}.csv`;
            link.click();

            showToast('结果已导出为CSV文件', 'success');
        } catch (error) {
            console.error('导出失败:', error);
            showToast('导出失败', 'error');
        }
    }

    // 刷新日志
    function refreshLogs() {
        loadSqlLogs();
        showToast('日志已刷新', 'success');
    }

    // 清空日志
    function clearLogs() {
        if (confirm('确定要清空所有SQL日志吗？')) {
            fetch('/sqlLog/clear', {method: 'POST'})
                .then(response => response.text())
                .then(result => {
                    if (result === 'success') {
                        allLogs = [];
                        filteredLogs = [];
                        updateStats();
                        renderLogs();
                        showToast('日志已清空', 'success');
                    } else {
                        showToast('清空失败', 'error');
                    }
                })
                .catch(error => {
                    console.error('清空失败:', error);
                    showToast('清空失败', 'error');
                });
        }
    }

    // 退出登录
    function logout() {
        if (confirm('确定要退出登录吗？')) {
            fetch('/sqlLog/logout', {method: 'POST'})
                .then(() => {
                    showLoginOverlay();
                })
                .catch(error => {
                    console.error('退出失败:', error);
                    showLoginOverlay();
                });
        }
    }

    // 显示提示消息
    function showToast(message, type = 'success') {
        const toast = document.createElement('div');
        toast.className = `toast ${type}`;
        toast.textContent = message;
        document.body.appendChild(toast);

        setTimeout(() => {
            toast.classList.add('show');
        }, 100);

        setTimeout(() => {
            toast.classList.remove('show');
            setTimeout(() => {
                document.body.removeChild(toast);
            }, 300);
        }, 3000);
    }
</script>
</body>
</html> 